package com.dxysun.springboot.config;

import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.joran.spi.JoranException;
import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.ConfigChangeListener;
import com.ctrip.framework.apollo.ConfigService;
import com.ctrip.framework.apollo.model.ConfigChangeEvent;
import com.ctrip.framework.apollo.spring.config.PropertySourcesConstants;
import org.slf4j.ILoggerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.Ordered;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.util.StringUtils;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.ByteArrayInputStream;
import java.io.UnsupportedEncodingException;

//@Component
public class LoggerRefresher implements ApplicationContextInitializer<ConfigurableApplicationContext>, EnvironmentPostProcessor, Ordered {
    private static final Logger log = LoggerFactory.getLogger(LoggerRefresher.class);

    private boolean loadFlag = false;

    @Override
    public void initialize(ConfigurableApplicationContext context) {
        ConfigurableEnvironment environment = context.getEnvironment();
        load(environment);

    }

    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        load(environment);
    }

    @Override
    public int getOrder() {
        return 1;
    }

    private void load(ConfigurableEnvironment environment) {
        if (!loadFlag) {
            environment.getPropertySources().forEach(ps -> {
                if (PropertySourcesConstants.APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME.equals(ps.getName())) {
                    configureByApollo();
                    loadFlag = true;
                }
            });
        }
    }

    private void configureByApollo() {
        Config config = ConfigService.getConfig("logback.xml");

        String content = config.getProperty("content", "");
        if (StringUtils.isEmpty(content) || !validateXML(content)) {
            return;
        }

        config.addChangeListener(new ConfigChangeListener() {
            @Override
            public void onChange(ConfigChangeEvent changeEvent) {
                configureByApollo();
            }

            @Override
            public boolean equals(Object obj) {
                if (this == obj) {
                    return true;
                }
                if (this.getClass().equals(obj.getClass())) {
                    return true;
                }
                return false;
            }

            @Override
            public int hashCode() {
                return 1;
            }
        });

        ILoggerFactory loggerFactory = LoggerFactory.getILoggerFactory();
        LoggerContext loggerContext = (LoggerContext) loggerFactory;
        loggerContext.reset();
        JoranConfigurator configurator = new JoranConfigurator();
        configurator.setContext(loggerContext);
        try {
            configurator.doConfigure(new ByteArrayInputStream(content.getBytes("utf-8")));
            log.warn("*****************************logback configureByApollo success!********************************");
        } catch (JoranException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }

    private boolean validateXML(String xml){
        boolean isValidated = true;
        try {
            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = documentBuilderFactory.newDocumentBuilder();
            builder.parse(new ByteArrayInputStream(xml.getBytes("utf-8")));
        } catch (Exception e) {
            log.error("apollo logback config error = {}", e);
            isValidated = false;
        }
        return isValidated;
    }

}
